# -*- coding: UTF-8 -*-
# @description : python
# @Author : zyl
# @contact : zyl@mxsoft.com
# @Time : 2021/9/6 16:00
# @Remark: 监控配置DB
import logging
import base64

from mxsoftpy import DB
from mxsoftpy.TreeDB import symbol_map
from mxsoftpy.db_def.def_type import type_map
from mxsoftpy.exception import ParamsError, DBError
from utils.conf.mxconfig import MxConfig
from mxsoftpy.db_def.def_tree import TRDB_OPKF_OPENEXIST
from superbsapi import web_decrypt, DecryptString, EncryptString


class MonitorConfigDB(DB):

    def check_ip_label(self, data):
        """
        检查IP和名称是否重复
        :param data:
        :return:
        """
        self.tree.open('VideoMonitor', 'Config', file='IOT', host=MxConfig.HOST, port=MxConfig.PORT)
        if data['MonitorName']:
            monitor_name_expression = [
                {"name": "MonitorName", "nCondition": symbol_map['e'], "vLiData": data['MonitorName'],
                 "vLiDataType": type_map['str']}]
            monitorName_where = ' 0'
            if 'id' in data:
                monitor_name_expression.append(
                    {"name": "id", "nCondition": symbol_map['ne'], "vLiData": int(data['id']),
                     "vLiDataType": type_map['int']})
            monitorName_where += ' and 1'
            monitor_name_key = list()
            self.tree.exec_bs('bs_treedb_query_subkey_by_condition', monitor_name_expression, monitorName_where,
                              monitor_name_key, 0, 0)
            if monitor_name_key:
                raise Exception('%s 名称已存在' % data['MonitorName'])

        if data['CameraIp']:
            CameraIp_expression = [{"name": "CameraIp", "nCondition": symbol_map['e'], "vLiData": data['CameraIp'],
                                    "vLiDataType": type_map['str']}]
            CameraIp_where = '0'
            if 'id' in data:
                CameraIp_expression.append({"name": "id", "nCondition": symbol_map['ne'], "vLiData": int(data['id']),
                                            "vLiDataType": type_map['int']})
            CameraIp_where += ' and 1'
            CameraIp_key = list()
            self.tree.exec_bs('bs_treedb_query_subkey_by_condition', CameraIp_expression, CameraIp_where, CameraIp_key,
                              0, 0)
            if CameraIp_key:
                raise Exception('%s 摄像头IP已存在' % data['CameraIp'])

    def create(self, **kwargs) -> int:
        """
        添加视频监控组信息
        :param kwargs: 参数字典
        :return: 添加得主键ID 字符串
        """
        if kwargs['pwd']:
            if 'is_import' not in kwargs:
                vlist = kwargs['v_python'].split(';')
                kwargs['pwd'] = web_decrypt(kwargs['pwd'], vlist[0])
                sbool, kwargs['pwd'] = DecryptString(kwargs['pwd'])
                pwd = kwargs['pwd']
                sbool, kwargs['pwd'] = EncryptString(kwargs['pwd'])
            else:
                pwd = kwargs['pwd']
                sbool, kwargs['pwd'] = EncryptString(kwargs['pwd'])
        else:
            pwd = kwargs['pwd']
        try:
            self.tree.open('VideoMonitor', 'Config', file='IOT', host=MxConfig.HOST, port=MxConfig.PORT)
            # self.tree.exec_tree('Treedb_BeginTransaction')
            self.check_ip_label(kwargs)
            # self.tree.begin()
            items = list()
            for k, v in kwargs.items():
                if k in ['RtspPort', 'Port', 'GroupId', 'MonitorNumber']:
                    items.append((k, int(v), 'int'))
                else:
                    items.append((k, v))
            srtspUrl = r'rtsp://' + kwargs['UserName'] + ':' + pwd + '@' + kwargs['CameraIp'] + ':' + str(kwargs[
                'RtspPort']) + '/Streaming/Channels/' + str(kwargs['ChannelNumber'])
            srtspUrl = base64.b64encode(srtspUrl.encode(encoding='utf-8')).decode()
            sres = self.tree.insert_key_items(items)
            self.tree.exec_tree('Treedb_ReopenSubKey', 'Config\\' + sres, TRDB_OPKF_OPENEXIST)
            self.tree.insert_item('id', int(sres), 'int')
            self.tree.insert_item('rtspUrl', srtspUrl, 'str')
            # self.tree.exec_tree('Treedb_CommitTransaction')
            # self.tree.commit()
            return sres
        except DBError as e:
            # self.tree.exec_tree('Treedb_RollbackTransaction')
            # self.tree.rollback()
            logging.error('添加配置失败, %s' % str(e))
            raise ParamsError('获取数据失败，%s' % str(e))

    def loopData(self, data, groupid, result):
        """
        递归获取数据
        :param data: 数据字典
        :param groupid: 组ID
        :param result: 返回数据字典
        :return:
        """
        for key, val in data.items():
            if val['parent'] == groupid:
                result.append(key)
                self.loopData(data, key, result)

    def GetGroup(self, groupid):
        """
        获取分组下级
        :param groupid: 组ID
        :return:
        """
        self.tree.open('VideoMonitor', 'Group', file='IOT', host=MxConfig.HOST, port=MxConfig.PORT)
        data = []
        result = {}
        self.tree.exec_bs('bs_treedb_get_subkey_properties', [], [], result)
        self.loopData(result, groupid, data)
        data.append(groupid)
        return data

    def config_dict(self, **kwargs) -> dict:
        """
        返回配置列表
        :param kwargs: 查询得参数字典
        :return: 配置数据 字典， 配置主键 列表， 配置大小 int
        """

        key = list()
        if kwargs['GroupId'] == '1':
            conditions = '0 '
            QIS = [{"name": "id", "nCondition": symbol_map['ne'], "vLiData": 0, "vLiDataType": type_map['int']}]
        else:
            QIS = list()
            groups_list = self.GetGroup(kwargs['GroupId'])
            conditions = '('
            for k, id in enumerate(groups_list):
                QIS.append({"name": "GroupId", "nCondition": symbol_map['e'], "vLiData": int(id),
                            "vLiDataType": type_map['int']})
                conditions += str(k) + ' or '
            conditions = conditions[:-3] + ' )'

        self.tree.open('VideoMonitor', 'Config', file='IOT', host=MxConfig.HOST, port=MxConfig.PORT)

        # 搜索
        if 'Search' in kwargs and len(kwargs['Search']) > 0:
            QIS.append(
                {"name": "MonitorName", "nCondition": symbol_map['nclike'], "vLiData": '*' + kwargs['Search'] + '*',
                 "vLiDataType": type_map['str']})

            conditions += ' and ' + str(len(QIS) - 1)
        dataCount_int = self.tree.exec_bs('bs_treedb_query_subkey_by_condition', QIS, conditions, [], 0, 0)
        size_int = (int(kwargs['page_index']) - 1) * int(kwargs['page_size'])
        self.tree.exec_bs('bs_treedb_query_subkey_by_condition_ex', QIS, conditions, key, int(kwargs['page_size']),
                          size_int, kwargs['order_by'], kwargs['is_desc'])

        result = dict()
        self.tree.exec_bs('bs_treedb_get_subkey_properties', key,
                          ['MonitorNumber', 'CameraIp', 'MonitorName', 'GroupId', 'rtspUrl', 'id', 'server_ip'], result)

        return result, key, dataCount_int

    def delete(self, sdelId) -> int:
        """
        删除配置信息
        :param delId: 主键ID，字符串  多个以;隔开
        :return: 删除得主键 字符串
        """
        if sdelId:
            try:
                if sdelId.find(';') == -1:
                    self.tree.open('VideoMonitor', 'Config\\' + sdelId, file='IOT',
                                   host=MxConfig.HOST, port=MxConfig.PORT).delete()
                else:
                    delIds_list = sdelId.split(';')
                    for id in delIds_list:
                        self.tree.open('VideoMonitor', 'Config\\' + id, file='IOT',
                                       host=MxConfig.HOST, port=MxConfig.PORT).delete()
            except DBError as e:
                logging.error('删除视频失败, %s' % str(e))
        return sdelId

    def update(self, sId, **kwargs) -> str:
        """
        更新配置信息
        :param sId: 主键ID 字符串
        :param kwargs: 数据 字典
        :return: 更新得主键ID 字符串
        """
        if kwargs['pwd']:
            vlist = kwargs['v_python'].split(';')
            kwargs['pwd'] = web_decrypt(kwargs['pwd'], vlist[0])
            sbool, kwargs['pwd'] = DecryptString(kwargs['pwd'])
            pwd = kwargs['pwd']
            sbool, kwargs['pwd'] = EncryptString(kwargs['pwd'])
        else:
            pwd = kwargs['pwd']
        try:
            self.check_ip_label(kwargs)
            self.tree.open('VideoMonitor', 'Config\\' + sId, file='IOT',
                           host=MxConfig.HOST, port=MxConfig.PORT)
            properties = list()
            self.tree.begin()
            for k, v in kwargs.items():
                if k in ['RtspPort', 'Port', 'GroupId', 'id', 'MonitorNumber']:
                    valuetype = type_map['int']
                    v = int(v)
                else:
                    valuetype = type_map['str']
                properties.append({'name': k, 'value': v, 'valuetype': valuetype})
            srtspUrl = r'rtsp://' + kwargs['UserName'] + ':' + pwd + '@' + kwargs['CameraIp'] + ':' + kwargs[
                'RtspPort'] + '/Streaming/Channels/' + kwargs['ChannelNumber']
            srtspUrl = base64.b64encode(srtspUrl.encode(encoding='utf-8')).decode()
            properties.append({'name': 'rtspUrl', 'value': srtspUrl, 'valuetype': type_map['str']})
            self.tree.exec_bs('bs_treedb_insert_properties', properties, True)
            self.tree.commit()
            return sId
        except DBError as e:
            self.tree.rollback()
            logging.error('修改配置失败, %s' % str(e))
            raise ParamsError('获取数据失败，%s' % str(e))

    def retrieve(self, sid):
        """
        回显数据
        :param sid: 主键ID 多个以;隔开
        :return: 配置列表
        """
        self.tree.open('VideoMonitor', 'Config', file='IOT',
                       host=MxConfig.HOST, port=MxConfig.PORT).items()
        result = list()
        if sid.find(';'):
            ids = sid.split(';')
            for configId in ids:
                result.append(self.tree.open('Config\\' + configId).items())
            return result
        else:
            return self.tree.open('Config\\' + sid).items()

    def move(self, **kwargs):
        """
        批量移动
        :param kwargs 参数字典:  ConfigId 配置ID 字符串 多个监控以;隔开
        :return: 字符串主键ID
        """
        try:
            self.tree.open('VideoMonitor', 'Config', file='IOT',
                           host=MxConfig.HOST, port=MxConfig.PORT)
            self.tree.begin()
            ConfigIds_list = kwargs['ConfigId'].split(';')
            for id in ConfigIds_list:
                self.tree.open('Config\\' + id).insert_item('GroupId', int(kwargs['GroupId']))
            self.tree.commit()
            return kwargs['ConfigId']
        except DBError as e:
            self.tree.rollback()
            logging.error('修改配置失败, %s' % str(e))
            raise DBError('修改数据失败, %d' % str(e))

    def sort(self, **kwargs):
        """
        批量排序
        :param kwargs: 前端参数 字典
        :param data:  列表
        :return: 返回成功True
        """
        try:
            self.tree.open('VideoMonitor', '', file='IOT',
                           host=MxConfig.HOST, port=MxConfig.PORT)
            self.tree.begin()
            for val in kwargs['data']:
                self.tree.open('Config\\' + str(val['id'])).insert_item('MonitorNumber', int(val['MonitorNumber']))
            self.tree.commit()
            return True
        except DBError as e:
            self.tree.rollback()
            logging.error('排序失败, %s' % str(e))
            raise DBError('修改数据失败, %d' % str(e))
